﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

namespace Lightray.Hattrick.ChppLib
{
    public class ClockThread
    {
        private Stopwatch _stopwatch;
        private bool _resyncTime;
        private bool _externalUpdate;
        private Thread _clockThread;
        private IntPtr _timerHandle;
        private EventWaitHandle _initClockEvent;
        private DateTime _externalTime;

        public DateTime CurrentTime { get; private set; }
        
        public ClockThread()
        {
            _resyncTime = false;
            _externalUpdate = false;
            _clockThread = null;
            _timerHandle = IntPtr.Zero;
            _externalTime = DateTime.MinValue;

            _initClockEvent = new EventWaitHandle(false, EventResetMode.ManualReset);
            CurrentTime = DateTime.MinValue;            
        }

        public void Start()
        {
            if (_clockThread != null)
            {
                _clockThread.Abort();
                _clockThread.Join();
                _clockThread = null;
            }

            _clockThread = new Thread(() =>
            {
                SystemEvents.TimerElapsed += new TimerElapsedEventHandler(SystemEvents_TimerElapsed);
                SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
                
                CurrentTime = TimeScraper.ScrapeTime();
                _initClockEvent.Set();

                _stopwatch = Stopwatch.StartNew();
                _timerHandle = SystemEvents.CreateTimer(1000);

                Application.Run();
            });

            _clockThread.IsBackground = true;
            _clockThread.Start();
        }

        public void Stop()
        {
            cleanupSystemEvents();
        }        

        private void cleanupSystemEvents()
        {
            try
            {
                SystemEvents.KillTimer(_timerHandle);
                SystemEvents.TimerElapsed -= new TimerElapsedEventHandler(SystemEvents_TimerElapsed);
                SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
            }
            catch { } 
        }

        // TODO: post resume, fix time if unable to resync using internet
        private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            switch (e.Mode)
            {
                case PowerModes.Resume:
                    _resyncTime = true;
                    break;
                case PowerModes.StatusChange:
                    break;
                case PowerModes.Suspend:
                    break;
                default:
                    break;
            }
        }

        public void SetTime(DateTime time)
        {
            _externalUpdate = true;
            _externalTime = time;
        }

        // TODO: need to think what happans when exception in timer oocuress
        // TOOD: need to handle case: no internet! what now?
        private void SystemEvents_TimerElapsed(object sender, TimerElapsedEventArgs e)
        {
            if (_resyncTime)
            {
                CurrentTime = TimeScraper.ScrapeTime();
                _resyncTime = false;
                Debug.WriteLine("Time Resynced");
            }
            else if (_externalUpdate)
            {                
                CurrentTime = _externalTime;
                _externalUpdate = false;
                _externalTime = DateTime.MinValue;
                Debug.WriteLine("Updated time from external source");
            }
            else
                CurrentTime = CurrentTime.Add(_stopwatch.Elapsed);

            _stopwatch = Stopwatch.StartNew();
        }

        public bool WaitForInitialClock()
        {
            _initClockEvent.WaitOne();
            return true; // TODO: for now?
        }


    }
}
